AngularJSとRuby on Railsで作るCRUDアプリ – (3)Create
はじめに
前回構築したAngularJS+Ruby on Railsのアプリに
今回はCRUDの内のCreate機能を実装し、ウィスキーの情報を登録する画面を作成しました。
画面遷移としては
・一覧画面(index.html.erb)よりリンクをクリックし、登録画面(new.html.erb)に遷移する
・登録画面でボタンを押下すると、AngularJSにより非同期でサーバを呼び出し、登録する
・登録後、AngularJSにより一覧画面に遷移する
というようにしました。
以下に、実装する上でのポイントとなる箇所を記述していきます。
尚、ソースコードは以下のGitHubに置いてあるので、全ソースを見たい方は参考にしてください。
AngularjsWhiskyList
実装について
1.ルーティング
routes.rbに以下のように記述し、whiskyモデルに対するCRUDのルーティングを定義します。
routes.rb
root "whiskies#index" get "whiskies/list" resources :whiskies
2.登録画面
登録画面であるnew.html.erbです。
new.html.erb
<h1>Whiskies#new</h1> <div ng-controller="WhiskiesNewCtrl"> <div>Name</div><div><input type="text" ng-model="name"></div> <div>Price</div><div><input type="text" ng-model="price"></div> <button ng-click='Create();' class="btn-primary">Create</button> </div>
「ng-controller="WhiskiesNewCtrl"」でAngularJSのコントローラを指定し
「button ng-click='Create();'」でボタン押下時に実行する
AngularJSのメソッドを指定しています。
また「ng-model=・・・」を使い、textboxの入力値をAngularJSに紐付けています。
後述しますが「ng-model=・・・」を使うと、AngularJSのControllerで、指定した名称で入力値を参照できるようになります。
3.一覧画面
トップページである一覧画面に、登録画面へのリンクを追加します。
index.html.erb
<h1>Whiskies#index</h1> <%= link_to "new whisky", new_whisky_path, :class => 'btn btn-mini' %> <div ng-controller="WhiskiesCtrl"> <ul> <li ng-repeat="whisky in data"> {{whisky.name}} <p>${{whisky.price}}</p> </li> </ul> </div>
「link_to・・・」というのが、登録画面へのリンクです。
ただし、このままでは登録画面に遷移はしますが、次画面でAngularJSのコードが読み込まれません。
4.TurboLinkの無効化
Rails4からはTurboLinkがデフォルトで有効となっていますが
TurboLinkが有効である場合、遷移先の画面でAngularJSが読み込まれない事象が発生します。
このため、TurboLinkを無効にするのが、手っ取り早い対応法かと思われます。
対応法は
・application.jsの「//= require turbolinks」を消去
・application.html.erbの「stylesheet_link_tag」「javascript_include_tag」より
「"data-turbolinks-track" => true 」を消去
することです。
参考
Bootstrapping an AngularJS app in Rails 4.0 - Part 1
5.RailsのController
whiskies_controller.rb
def new end def create whisky = Whisky.new(:name => params[:name], :price => params[:price]) whisky.save render :nothing => true end
登録画面(new.html.erb)を表示するためのnewアクションと、データを登録するためのcreateアクションです。
createアクションは、後ほど書くAngularJSより呼び出され、データを登録します。
非同期通信で呼び出されるので画面を返却しないよう、「render :nothing・・・」としてあります。
5.AngularJSのController
いよいよ、AngularJSについてです。
上述した通り、登録画面のボタンを押下すると呼び出され、Railsのcreateアクションを呼び出します。
controllers.js
'use strict'; /* Controllers */ var whiskiesListApp = angular.module('whiskiesListApp', []); whiskiesListApp.config( ["$httpProvider", function($httpProvider) { $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content'); } ] ); (中略) whiskiesListApp.controller('WhiskiesNewCtrl', function ($scope, $http, $window) { $scope.Create = function() { $http.post('/whiskies', {'name': $scope.name, 'price': $scope.price} ).success(function(data, status, headers, config) { $window.location.href = '/' }).error(function(data, status) { console.log('error:' + status); }); } });
先ずは「whiskiesListApp.controller('WhiskiesNewCtrl・・・」の所を見ていきます。
「$http.post('/whiskies', {'name': $scope.name, 'price': $scope.price}」は
・「.post('/whiskies'」で、Post先のURLを指定
・「{'name': $scope.name, 'price': $scope.price}」で、入力値をハッシュ形式でPostの引数として渡す
ことを行っています。
次にPostが正常に終了した場合、「$window.location.href = '/'」でルートパスに遷移するようにしています。
ここでルートパス、'/whiskies'について確認するため $ rake routes を行うと、以下のようになります。
root GET / whiskies#index whiskies_list GET /whiskies/list(.:format) whiskies#list whiskies GET /whiskies(.:format) whiskies#index POST /whiskies(.:format) whiskies#create
・ルートパス「/」は前回作成したindexアクションが
・「whiskies」でPostするとcreateアクションが
実行されることが分かるかと思います。
次に、「whiskiesListApp.config(・・・」についてです。
Railsでは、AngularJS(を含むAjax通信)でPostする場合、認証用のトークンを送らないと「422」エラーとなることがあります。
このため、認証用トークンを渡すため「whiskiesListApp.config(・・・」にて、トークンを設定しています。
最後に
以上です。
・TurboLinkを無効化する
・認証用のトークンを渡す
と、ちょっとRailsの癖を考慮する必要がありました。